﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "ISelectionChangeEventHandler.h"
#include "ISelection.h"
#include "ISelectionChangeEvent.h"
#include "ISelectionChangeEventArgs.h"
#include "IDocument.h"
#include "IDrawingPolyCurve.h"
#include "ICurve2d.h"
#include "IGenericElement.h"
#include "GDDrawing/IDimensionBase.h"
#include "GDDrawing/DrawingCommandIds.h"
#include "GDDrawing/IDetailCurve.h"
#include "GDDrawing/DimensionTypeDefine.h"
#include "UniIdentity.h"
#include "IElementBasicInformation.h"
#include "DynamicPanel.h"
#include "IImportCADElement.h"
#include "IFilledRegion.h"
#include "GDDrawing/DrawingBuiltInCategoryUniIdentities.h"
using namespace gcmp;
using namespace gdmp;

namespace Sample
{
    /// 监听选择集变化，根据选择集内容更新辅助面板
    class DrawingSelectionChangeEventHandler : public gcmp::ISelectionChangeEventHandler
    {
    public:
        DrawingSelectionChangeEventHandler();
        ~DrawingSelectionChangeEventHandler();

        void UpdateAssistantPanel(
            const std::wstring& caption,
            const std::vector<std::wstring>& commands
        );
        void ClearAssistantPanel();

        bool IsAllPolyCurves(const gcmp::IDocument* pDoc);
        bool IsAllNurbsCurves(const gcmp::IDocument* pDoc);
        ///选择集中是否是标注及对应的标注类型
        bool IsDimension(const gcmp::IDocument* pDoc, DimensionType& type);
        bool IsImportCADElement(const gcmp::IDocument* pDoc);
        bool IsFilledRegion(const gcmp::IDocument* pDoc);
    private:
        virtual void On(gcmp::ISelectionChangeEventArgs* pArgs) override;
    };

    DrawingSelectionChangeEventHandler::DrawingSelectionChangeEventHandler()
    {
        ISelection* pSelection = ISelection::Get();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pSelection, L"断言`pSelection`失败",L"GDMPLab",L"2024-03-30");
        ISelectionChangeEvent* pSelectionChangeEvent = pSelection->GetSelectionChangeEvent();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pSelectionChangeEvent, L"断言`pSelectionChangeEvent`失败",L"GDMPLab",L"2024-03-30");
        pSelectionChangeEvent->Add(this);
    }

    DrawingSelectionChangeEventHandler::~DrawingSelectionChangeEventHandler()
    {
        ISelection* pSelection = ISelection::Get();
        if (pSelection)
        {
            ISelectionChangeEvent* pSelectionChangeEvent = pSelection->GetSelectionChangeEvent();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pSelectionChangeEvent, L"pSelectionChangeEvent",L"GDMPLab",L"2024-03-30");
            pSelectionChangeEvent->Delete(this);
        }
    }

    void DrawingSelectionChangeEventHandler::UpdateAssistantPanel(const std::wstring& caption, const std::vector<std::wstring>& commands)
    {
        if (DynamicPanel* pDynamicPanel = DynamicPanel::Get(L"AssistantPanel"))
        {
            pDynamicPanel->Update(caption, commands);
        }
    }

    void DrawingSelectionChangeEventHandler::ClearAssistantPanel()
    {
        if (DynamicPanel* pDynamicPanel = DynamicPanel::Get(L"AssistantPanel",false))
        {
            pDynamicPanel->Update(L"", {});
        }
    }

    bool DrawingSelectionChangeEventHandler::IsAllPolyCurves(const gcmp::IDocument* pDoc)
    {
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"断言`pDoc`失败",L"GDMPLab",L"2024-03-30");
        ISelection* pSelection = ISelection::Get();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pSelection, L"断言`pSelection`失败",L"GDMPLab",L"2024-03-30");

        std::unordered_set<ElementId, ElementIdHash> selectElementIds = pSelection->GetSelectedElements();
        for (auto& elementId : selectElementIds)
        {
            if (!elementId.IsValid())
                continue;
            const gcmp::IElement* pElement = pDoc->GetElement(elementId);
            if (pElement == nullptr)
                continue;

            const gcmp::IGenericElement* pGenericElement = quick_cast<gcmp::IGenericElement>(pElement);
            if (!pGenericElement)
                return false;

            const gcmp::IDrawingPolyCurve* pDrawingPolyCurve = quick_cast<gcmp::IDrawingPolyCurve>(pGenericElement->GetExternalObject());
            if (!pDrawingPolyCurve)
                return false;
        }
        return true;
    }

    bool DrawingSelectionChangeEventHandler::IsAllNurbsCurves(const gcmp::IDocument* pDoc)
    {
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"断言`pDoc`失败",L"GDMPLab",L"2024-03-30");
        ISelection* pSelection = ISelection::Get();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pSelection, L"断言`pSelection`失败",L"GDMPLab",L"2024-03-30");

        std::unordered_set<ElementId, ElementIdHash> selectElementIds = pSelection->GetSelectedElements();
        for (auto& elementId : selectElementIds)
        {
            if (!elementId.IsValid())
                continue;
            const gcmp::IElement* pElement = pDoc->GetElement(elementId);
            if (pElement == nullptr)
                continue;

            const gdmp::IDetailCurve* pDetailCurve = gdmp::IDetailCurve::Cast(pElement);
            if (!pDetailCurve)
                return false;

            const gcmp::ICurve2d* pCurve2d = pDetailCurve->GetCurve2d();
            if (!pCurve2d)
                return false;
            gcmp::GeometryType geometryType = pCurve2d->GetType();
            if (geometryType != GeometryType::NurbsCurve2d)
            {
                return false;
            }
        }
        return true;
    }

    bool DrawingSelectionChangeEventHandler::IsDimension(const gcmp::IDocument* pDoc, DimensionType& type)
    {
        type = DimensionType::Unknown;
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc,L"断言`pDoc`失败",L"GDMPLab",L"2024-03-30");
        ISelection* pSelection = ISelection::Get();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pSelection, L"断言`pSelection`失败",L"GDMPLab",L"2024-03-30");
        std::unordered_set<ElementId, ElementIdHash> selectElementIds = pSelection->GetSelectedElements();
        if (selectElementIds.empty() || selectElementIds.size() > 1)          //选择集大于1或为0 返回DimensionType::Unknown
            return false;
        else
        {
            ElementId id = *selectElementIds.begin();
            if (!id.IsValid())
                return false;
            const IDimensionBase* pDimBase = IDimensionBase::Get(pDoc, id);  ///选择集中的内容是否是标注
            if (pDimBase)
                type = pDimBase->GetDimensionType();
        }

        ///径向(直径、半径)标注不支持编辑功能，仅线性、对齐、角度、弧长标注支持
        if (type == DimensionType::Aligned || type == DimensionType::Angular || type == DimensionType::Linear || type == DimensionType::ArcLength)
            return true;
        else
            return false;
    }

    bool DrawingSelectionChangeEventHandler::IsImportCADElement(const gcmp::IDocument* pDoc)
    {
        const auto& selections = ISelection::Get()->GetSelectedElements();
        if (!selections.empty())
        {
            ElementId elemId = *selections.begin();
            IElement* pElement = pDoc->GetElement(elemId);
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pElement, L"pElement为空",L"GDMPLab",L"2024-03-30");
            IImportCADElement* pGEle = quick_cast<IImportCADElement>(pElement);
            if (pGEle && selections.size() == 1)
                return true;
        }

        return false;
    }

    bool DrawingSelectionChangeEventHandler::IsFilledRegion(const gcmp::IDocument* pDoc)
    {
        if (pDoc == nullptr)
            return false;
        ISelection* pSelection = ISelection::Get();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pSelection, L"断言`pSelection`失败",L"GDMPLab",L"2024-03-30");
        std::unordered_set<ElementId, ElementIdHash> selectElementIds = pSelection->GetSelectedElements();
        if (selectElementIds.empty() || selectElementIds.size() > 1)
            return false;
        else
        {
            ElementId id = *selectElementIds.begin();
            if (!id.IsValid())
                return false;
            IElement* pElement = pDoc->GetElement(id);
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pElement, L"断言`pElement`失败",L"GDMPLab",L"2024-03-30");
            IGenericElement* pGEle = quick_cast<IGenericElement>(pElement);
            if (!pGEle)
                return false;

            IFilledRegion* pFilledRegion = quick_cast<IFilledRegion>(pGEle->GetExternalObject());
            if (pFilledRegion)
                return true;
        }
        return false;
    }

    void DrawingSelectionChangeEventHandler::On(gcmp::ISelectionChangeEventArgs* pArgs)
    {
        DBG_WARN_AND_RETURN_VOID_UNLESS(pArgs, L"断言`pArgs`失败",L"GDMPLab",L"2024-03-30");
        const gcmp::IDocument* pDoc = pArgs->GetDocument();

        if (pDoc && pDoc->IsReadonlyForSharingViolation())
            return;
        ISelection* pSelection = ISelection::Get();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pSelection, L"断言`pSelection`失败",L"GDMPLab",L"2024-03-30");
        //如果选择集为空,则清空辅助面板
        if (pSelection->GetSelectedElements().empty()) {
            ClearAssistantPanel();
            return;
        }

        DimensionType type{ DimensionType::Unknown };
        std::vector<std::wstring> commands;
        std::wstring caption = L"";
        if (IsAllPolyCurves(pDoc)) {
            commands.emplace_back(gdmp::CommandId::PolyCurveConvertNurbsCurve);
            commands.emplace_back(gdmp::CommandId::PolyCurveConvertControlPointsNurbsCurve);
            caption = L"编辑多段线";
        }
        else if (IsAllNurbsCurves(pDoc))
        {
            commands.emplace_back(gdmp::CommandId::ConvertNurbsCurveToPolyCurve);
            caption = L"编辑样条曲线";
        }
        else if (IsDimension(pDoc, type))
        {
            caption = L"编辑标注";
            ///根据选择集中标注类型更新辅助面板中需要添加的命令情况
            if (type == DimensionType::Aligned || type == DimensionType::Linear)    ///线性&对齐标注支持合并尺寸区间、删除尺寸区间、编辑尺寸界线功能
            {
                commands.emplace_back(gdmp::CommandId::MergeDimensionInterval);
                commands.emplace_back(gdmp::CommandId::DeleteDimensionInterval);
                commands.emplace_back(gdmp::CommandId::EditDimensionWitnessLine);
            }
            else ///弧长、角度标注支持编辑尺寸界线功能，径向标注不支持(IsDimension()中对径向标注返回值做了处理，返回了false)
                commands.emplace_back(gdmp::CommandId::EditDimensionWitnessLine);  
        }
        else if (IsImportCADElement(pDoc))
        {
            commands.emplace_back(CommandId::CADImportShowLayerInfo);
            caption = L"编辑CAD图纸";
        }
        else if (IsFilledRegion(pDoc)) 
        {
            caption = L"编辑填充";
            commands.emplace_back(gdmp::CommandId::EditFilledRegion);
        }
        
        if (!commands.empty()) {
            UpdateAssistantPanel(caption, commands);
        }
    }

    namespace
    {
        //仅作为示例展示使用，构造时注册、析构时移除
        gcmp::OwnerPtr<DrawingSelectionChangeEventHandler> opStub{
            NEW_AS_OWNER_PTR(DrawingSelectionChangeEventHandler)
        };
    }
}
